package com.shao.utils.network;

import com.shao.SrpcBootstrap;
import com.shao.discovery.NettyBootstrapInitializer;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author PaoFu
 * @version 1.0
 * @data 2025/5/14 14:45
 */
@Slf4j
public class ChannelAndAddressUtils {

    /**
     * 获取一个可用的管道
     * @param address 链接地址
     * @return 返回可用的管道
     */
    public static Channel getAvalibleChannel(InetSocketAddress address) {
        Channel channel = SrpcBootstrap.SOCKET_CHANNEL.get(address);
        if (channel == null) {
            // 创建 channel
            CompletableFuture<Channel> channelFuture = new CompletableFuture<>();
            NettyBootstrapInitializer.getBootstrap().connect(address).addListener((ChannelFutureListener) promise -> {
                if (promise.isDone()) {
                    log.info("Create channel is done");
                    channelFuture.complete(promise.channel());
                } else if (!promise.isSuccess()) {
                    log.info("Create channel is fail");
                    channelFuture.completeExceptionally(promise.cause());
                }
            });
            try {
                channel = channelFuture.get(3, TimeUnit.SECONDS);
            } catch (InterruptedException | ExecutionException e) {
                log.error("获取或创建通道时发生异常");
                throw new RuntimeException(e);
            } catch (TimeoutException e) {
                // 超时后取消任务并释放资源
                channelFuture.cancel(true);
                log.error("SRPC 调用超时");
                throw new RuntimeException(e);
            }
            // 缓存新创建的channel
            log.info("channel链接已创建成功 --> {}", channel);
            SrpcBootstrap.SOCKET_CHANNEL.put(address, channel);
        }
        return channel;
    }
}
